#*******************************************************************************#
# BinaryCookieReader: Written By Satishb3 (http://www.securitylearn.net)        #
#                                                                               #
# For any bug fixes contact me: satishb3@securitylearn.net                      #
#                                                                               #
# Usage: Python BinaryCookieReader.py Cookie.Binarycookies-FilePath             #
#                                                                               #
# Safari browser and iOS applications store the persistent cookies in a binary  #
# file names Cookies.binarycookies.BinaryCookieReader is used to dump all the   #
# cookies from the binary Cookies.binarycookies file.                           #
#                                                                               #
#*******************************************************************************#

import sys
from struct import unpack
from StringIO import StringIO
from time import strftime, gmtime

if len(sys.argv)!=2:
	print "\nUsage: Python BinaryCookieReader.py [Full path to Cookies.binarycookies file] \n"
	print "Example: Python BinaryCookieReader.py C:\Cookies.binarycookies"
	sys.exit(0)
	
FilePath=sys.argv[1]

try:
	binary_file=open(FilePath,'rb')
except IOError as e:
	print 'File Not Found :'+ FilePath
	sys.exit(0)
   
file_header=binary_file.read(4)                             #File Magic String:cook 

if str(file_header)!='cook':
	print "Not a Cookies.binarycookie file"
	sys.exit(0)
	
num_pages=unpack('>i',binary_file.read(4))[0]               #Number of pages in the binary file: 4 bytes

page_sizes=[]
for np in range(num_pages):
	page_sizes.append(unpack('>i',binary_file.read(4))[0])  #Each page size: 4 bytes*number of pages
	
pages=[]
for ps in page_sizes:
	pages.append(binary_file.read(ps))                      #Grab individual pages and each page will contain >= one cookie

	
print "#*************************************************************************#"
print "# BinaryCookieReader: developed by Satishb3: http://www.securitylearn.net #"
print "#*************************************************************************#"

for page in pages:
	page=StringIO(page)                                     #Converts the string to a file. So that we can use read/write operations easily.
	page.read(4)                                            #page header: 4 bytes: Always 00000100
	num_cookies=unpack('<i',page.read(4))[0]                #Number of cookies in each page, first 4 bytes after the page header in every page.
	
	cookie_offsets=[]
	for nc in range(num_cookies):
		cookie_offsets.append(unpack('<i',page.read(4))[0]) #Every page contains >= one cookie. Fetch cookie starting point from page starting byte

	page.read(4)                                            #end of page header: Always 00000000

	cookie=''
	for offset in cookie_offsets:
		page.seek(offset)                                   #Move the page pointer to the cookie starting point
		cookiesize=unpack('<i',page.read(4))[0]             #fetch cookie size
		cookie=StringIO(page.read(cookiesize))              #read the complete cookie 
		
		cookie.read(4)                                      #unknown
		
		flags=unpack('<i',cookie.read(4))[0]                #Cookie flags:  1=secure, 4=httponly, 5=secure+httponly
		cookie_flags=''
		if flags==0:
			cookie_flags=''
		elif flags==1:
			cookie_flags='Secure'
		elif flags==4:
			cookie_flags='HttpOnly'
		elif flags==5:
			cookie_flags='Secure; HttpOnly'
		else:
			cookie_flags='Unknown'
			
		cookie.read(4)                                      #unknown
		
		urloffset=unpack('<i',cookie.read(4))[0]            #cookie domain offset from cookie starting point
		nameoffset=unpack('<i',cookie.read(4))[0]           #cookie name offset from cookie starting point
		pathoffset=unpack('<i',cookie.read(4))[0]           #cookie path offset from cookie starting point
		valueoffset=unpack('<i',cookie.read(4))[0]          #cookie value offset from cookie starting point
		
		endofcookie=cookie.read(8)                          #end of cookie
		                        
		expiry_date_epoch= unpack('<d',cookie.read(8))[0]+978307200          #Expiry date is in Mac epoch format: Starts from 1/Jan/2001
		expiry_date=strftime("%a, %d %b %Y ",gmtime(expiry_date_epoch))[:-1] #978307200 is unix epoch of  1/Jan/2001 //[:-1] strips the last space
				
		create_date_epoch=unpack('<d',cookie.read(8))[0]+978307200           #Cookies creation time
		create_date=strftime("%a, %d %b %Y ",gmtime(create_date_epoch))[:-1]
		#print create_date
		
		cookie.seek(urloffset-4)                            #fetch domaain value from url offset
		url=''
		u=cookie.read(1)
		while unpack('<b',u)[0]!=0:
			url=url+str(u)
			u=cookie.read(1)
				
		cookie.seek(nameoffset-4)                           #fetch cookie name from name offset
		name=''
		n=cookie.read(1)
		while unpack('<b',n)[0]!=0:
			name=name+str(n)
			n=cookie.read(1)
				
		cookie.seek(pathoffset-4)                          #fetch cookie path from path offset
		path=''
		pa=cookie.read(1)
		while unpack('<b',pa)[0]!=0:
			path=path+str(pa)
			pa=cookie.read(1)
				
		cookie.seek(valueoffset-4)                         #fetch cookie value from value offset
		value=''
		va=cookie.read(1)
		while unpack('<b',va)[0]!=0:
			value=value+str(va)
			va=cookie.read(1)
		
		print 'Cookie : '+name+'='+value+'; domain='+url+'; path='+path+'; '+'expires='+expiry_date+'; '+cookie_flags
		
binary_file.close()

